#include "nfa.h"
#include"namestorage.h"

NameStorage NFA::initNames() {
	NameStorage ns;
	std::string s = "_ACCEPT_";
	ns.addName(s);
	return ns;
}

NameStorage NFA::names = NFA::initNames();

NFAState NFA::feedString(NFAState const &nfastate, string const &str){
	
	NFAState tmpState=nfastate;
	//std::cout << tmpState.includesState(0) << " " << tmpState.includesState(1) << " " << tmpState.includesState(2) <<  std::endl;
	for (int i = 0; i < str.size(); i++){
		
		tmpState = feedTerminal(tmpState, str[i]);
		//std::cout << tmpState.includesState(0) << " " << tmpState.includesState(1) << " " << tmpState.includesState(2)<<  std::endl;
	}	
	return tmpState;	
}

NFAState NFA::feedString(unsigned st, string const &str){
	
	NFAState tmpState;
	
	tmpState = feedTerminal(st, str[0]);	

	for (unsigned i = 1; i < str.size(); i++){
		tmpState = feedTerminal(tmpState, str[i]);	
		
	}
	return tmpState;	
}

NFAState NFA::feedTerminal(unsigned st, char c){
	NFAState newState;

	for (unsigned i = 0; i < rules.size(); i++){

		if ((st == rules[i].from)
			&&(rules[i].on == c)){
					newState += rules[i].to;
					/*std::cout << rules[i].to << std::endl;
					for (int j = 0; j < newState.size(); j++){
						std::cout << newState.includesState(i) << " ";
					}
					std::cout << std::endl;*/
				}
	}
	return newState;
}

NFAState NFA::feedTerminal(NFAState const &st, char c){

	NFAState newState;
	for (unsigned k = 0; k<st.size(); k++){
		if (st.includesState(k)) newState += feedTerminal(k,c);		
	}
	return newState;
}


NFARule NFA::get_rule_from_stream(std::istream& in)
{
    std::vector<char> rule;
    string str;
    getline(in, str);
	
  //  std::cout << "str "<< str << std::endl;
    for( int i = 0; i != str.size(); ++i )
    { 
        if ( isalpha(str[i]) || isdigit(str[i])) {
            rule.push_back( str[i] ); 
	  //  std::cout << "rule: "<< rule[rule.size()-1] << std::endl;
	}
	
    }
 
    std::string left, right;
    left.push_back(rule[0]);
    if (rule.size() == 3)
	right.push_back(rule[2]);
 
    switch (rule.size())
    {
        case 3:
            	return NFARule(names.addName(left), rule[1], names.addName(right));
        case 2:	       
                return NFARule(names.addName(left), rule[1], (unsigned)0);
	default:
		return NFARule();
            
    }
 
   
}

std::istream & operator>>(std::istream &stream, NFA &nfa){
	
	std::string start;
	getline(stream, start);
	nfa.S = NFA::names.addName(start); // да, начальное состояние 1 - захардкодено
	while (stream.good()){
		//std::cout << 1 << std::endl;
		NFARule newRule = NFA::get_rule_from_stream(stream);
		nfa.rules.push_back(newRule);
		//std::cout << nfa.rules[nfa.rules.size()-1].from << " " << nfa.rules[nfa.rules.size()-1].on << " " << nfa.rules[nfa.rules.size()-1].to << std::endl;
		//std::cout << newRule.from << " " << newRule.on << " " << newRule.to << std::endl;
	}

	return stream;
}

std::ostream & operator<<(std::ostream &stream, NFA const & nfa) {
	stream << "digraph NFA {" << std::endl;
	stream << "\"" << NFA::names[nfa.S] << "\" [style = filled, color = yellow];" << std::endl;
	for(unsigned i = 0; i < nfa.rules.size(); i++)
		stream << "\"" << NFA::names[nfa.rules[i].from] << "\" -> \"" << NFA::names[nfa.rules[i].to] << "\" [label = \"" << nfa.rules[i].on << "\"];" << std::endl;
	stream << "}" << std::endl;
	return stream;
}
